package com.htsk.city.services.wechat.service;

import com.alibaba.fastjson2.JSON;
import com.htsk.city.services.core.dao.*;
import com.htsk.city.services.core.domain.*;
import com.htsk.city.services.core.entity.PageInfo;
import com.htsk.city.services.core.entity.R;
import com.htsk.city.services.core.enums.OrderStatus;
import com.htsk.city.services.wechat.params.OrderQueryParam;
import com.htsk.city.services.wechat.vo.OrderAddVo;
import com.htsk.city.services.core.entity.OrderVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.*;

/**
 * @Author 李树洪
 * @Email 2324592742@qq.com
 * @Date 2025/9/24 9:33
 */
@Service
@Slf4j
public class OrderService {

    @Resource
    private TechnicianDao technicianDao;
    @Resource
    private CityServiceSubCategoryDao cityServiceSubCategoryDao;
    @Resource
    private ServiceSubCategoryDao serviceSubCategoryDao;
    @Resource
    private OrderMasterDao orderMasterDao;
    @Resource
    private OrderItemDao orderItemDao;
    @Resource
    private OrderOperationLogDao orderOperationLogDao;
    @Resource
    private OrderReviewDao orderReviewDao;

    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    public R add(WxUser wxUser, OrderAddVo orderVo) {
        // 1. 获取师傅信息
        Optional<Technician> technician=technicianDao.findById(orderVo.getTechnicianId());
        if (!technician.isPresent()) {
            return R.fail("师傅不存在");
        }
        // 2. 获取服务信息
        Optional<ServiceSubCategory> serviceSubCategory = serviceSubCategoryDao.findById(orderVo.getServiceSubCategoryId());
        if (!serviceSubCategory.isPresent()) {
            return R.fail("相关服务不存在");
        }

        // 2. 获取城市服务信息
        CityServiceSubCategory cityServiceSubCategory=cityServiceSubCategoryDao.findByServiceSubCategoryIdAndCityId(orderVo.getServiceSubCategoryId(), wxUser.getCityId());
        if (cityServiceSubCategory == null || cityServiceSubCategory.getId() == null ) {
            return R.fail("该城市相关服务不存在");
        }
        // 检查用户对该师傅和服务是否有正在进行中的订单
        int count =orderMasterDao.existsByUserIdAndTechnicianIdAndStatusIn(wxUser.getId(),
                orderVo.getTechnicianId(),
                orderVo.getServiceSubCategoryId(),
                Arrays.asList(OrderStatus.PENDING.getKey(), OrderStatus.ACCEPTED.getKey()));
        if (count != 0) {
            return R.fail("用户已存在该师傅相同服务正在进行中的订单");
        }
        // 3. 创建订单主表
        OrderMaster orderMaster = new OrderMaster();
        orderMaster.setOrderNo(generateOrderNo("WX",wxUser.getId()));
        orderMaster.setAppId("appid");
        orderMaster.setOpenid(wxUser.getOpenId());
        orderMaster.setUserId(wxUser.getId());
        orderMaster.setOrderStatus((byte) OrderStatus.PENDING.getKey());
        orderMaster.setUserMobile(wxUser.getMobile());
        // 服务金额
        BigDecimal totalAmount = cityServiceSubCategory.getServicePrice();
        // 优惠金额
        BigDecimal discountAmount = orderVo.getDiscountAmount()==null?BigDecimal.ZERO:orderVo.getDiscountAmount();
        // 实际支付金额
        BigDecimal payAmount = totalAmount.subtract(discountAmount);
        orderMaster.setTotalAmount(totalAmount);
        orderMaster.setDiscountAmount(discountAmount);
        orderMaster.setPayAmount(payAmount);
        orderMaster.setRemark(orderVo.getRemark());
        orderMaster.setSource((byte) 0);
        orderMaster.setIsDeleted((byte) 0);
        orderMaster.setCreateTime(Instant.now());
        orderMaster.setUpdateTime(Instant.now());
        OrderMaster order = orderMasterDao.save(orderMaster);

        // 4. 创建订单商品表
        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(order.getId());
        orderItem.setOrderNo(order.getOrderNo());
        orderItem.setPrice(cityServiceSubCategory.getServicePrice());
        orderItem.setQuantity(1);
        orderItem.setSubtotal(cityServiceSubCategory.getServicePrice());
        orderItem.setRefundStatus((byte) 0);
        orderItem.setCreateTime(Instant.now());
        orderItem.setUpdateTime(Instant.now());
        orderItem.setDescription(cityServiceSubCategory.getIntroduceText());
        orderItem.setAddress(orderVo.getAddress());
        orderItem.setUserLat(orderVo.getUserLat());
        orderItem.setUserLng(orderVo.getUserLng());
        orderItem.setServiceSubCategoryId(cityServiceSubCategory.getId());
        orderItem.setServiceSubCategoryName(serviceSubCategory.get().getServiceSubCategoryName());
        orderItem.setAppointmentTime(orderVo.getAppointmentTime());
        orderItem.setTechnicianId(technician.get().getId());
        orderItem.setTechnicianName(technician.get().getName());
        orderItem.setTechnicianMobile(technician.get().getMobile());
        orderItemDao.save(orderItem);
        addOrderLog(wxUser, orderMaster,"create","创建订单",orderVo,"ok");
        return R.ok();

    }

    private void addOrderLog(WxUser wxUser, OrderMaster orderMaster,String action, String content,Object request,Object response) {
        // 记录订单日志
        OrderOperationLog orderOperationLog = new OrderOperationLog();
        orderOperationLog.setOrderId(orderMaster.getId());
        orderOperationLog.setOrderNo(orderMaster.getOrderNo());
        orderOperationLog.setOperatorType((byte)1);
        orderOperationLog.setOperatorId(wxUser.getId());
        orderOperationLog.setOperatorName(wxUser.getNickname());
        orderOperationLog.setAction(action);
        orderOperationLog.setContent(content);
        // 判断request和response如果不是基本数据类型,则转换成json字符串
        if (request != null && !request.getClass().isPrimitive()) {
            request=JSON.toJSONString(request);
        }
        if (response != null && !response.getClass().isPrimitive()) {
            response=JSON.toJSONString(response);
        }
        orderOperationLog.setRequestJson(String.valueOf(request));
        orderOperationLog.setResponseJson(String.valueOf(response));
        orderOperationLog.setCreateTime(Instant.now());
        orderOperationLogDao.save(orderOperationLog);
    }


    public String generateOrderNo(String prefix, Long userId) {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String dateStr = sdf.format(new Date());

        Random random = new Random();
        String randomPart = String.format("%06d", random.nextInt(1000000));

        String bizType = "01"; // 01-普通订单 02-秒杀订单等

        String userPart = String.format("%04d", userId % 10000);
        // 前缀(2位) + 年月日(8位) + 业务类型(2位) + 自增序列(6位) + 用户ID(4位)
        return prefix + dateStr + bizType + randomPart + userPart;
    }
    @Transactional
    public R accept(WxUser wxUser, Long orderId) {
        if (wxUser.getUserType() != 2 || wxUser.getOrgId() == null){
            return R.fail("不能进行该操作");
        }
        Optional<OrderMaster> orderMasterOpt = orderMasterDao.findById(orderId);
        if (!orderMasterOpt.isPresent()) {
            return R.fail("订单不存在");
        }
        OrderMaster orderMaster = orderMasterOpt.get();
        if (orderMaster.getOrderStatus() != 0){
            return R.fail("订单状态异常,请刷新后重试");
        }
        OrderItem orderItem=orderItemDao.findByOrderId(orderId);
        if (!orderItem.getTechnicianId().equals(wxUser.getOrgId())){
            return R.fail("你不是该订单的师傅,不能进行该操作");
        }
        orderMaster.setOrderStatus((byte) OrderStatus.ACCEPTED.getKey());
        orderMaster.setDeliveryTime(Instant.now());
        orderMaster.setUpdateTime(Instant.now());
        orderMasterDao.save(orderMaster);
        addOrderLog(wxUser, orderMaster,"accept","师傅接单",orderMaster,"ok");
        return R.ok();
    }
    @Transactional
    public R refuse(WxUser wxUser, Long orderId) {
        if (wxUser.getUserType() != 2 || wxUser.getOrgId() == null){
            return R.fail("不能进行该操作");
        }
        Optional<OrderMaster> orderMasterOpt = orderMasterDao.findById(orderId);
        if (!orderMasterOpt.isPresent()) {
            return R.fail("订单不存在");
        }
        OrderMaster orderMaster = orderMasterOpt.get();
        if (orderMaster.getOrderStatus() != 0 && orderMaster.getOrderStatus() != 1){
            return R.fail("订单状态异常,请刷新后重试");
        }
        OrderItem orderItem=orderItemDao.findByOrderId(orderId);
        if (!orderItem.getTechnicianId().equals(wxUser.getOrgId())){
            return R.fail("你不是该订单的师傅,不能进行该操作");
        }
        orderMaster.setOrderStatus((byte) OrderStatus.REFUSE.getKey());
        orderMaster.setUpdateTime(Instant.now());
        orderMasterDao.save(orderMaster);
        if (orderMaster.getOrderStatus() == 0){
            addOrderLog(wxUser, orderMaster,"refuse","师傅拒绝接单",orderId,"ok");
        }else{
            addOrderLog(wxUser, orderMaster,"cancel","师傅取消订单",orderId,"ok");
        }

        return R.ok();
    }

    public R cancel(WxUser wxUser, Long orderId) {
        Optional<OrderMaster> orderMasterOpt = orderMasterDao.findById(orderId);
        if (!orderMasterOpt.isPresent()) {
            return R.fail("订单不存在");
        }
        OrderMaster orderMaster = orderMasterOpt.get();
        if (orderMaster.getOrderStatus() == 1){
            return R.fail("师傅已接单,请联系师傅取消订单");
        }
        if (orderMaster.getOrderStatus() != 0){
            return R.fail("订单状态异常,请刷新后重试");
        }
        if (!orderMaster.getUserId().equals(wxUser.getId())){
            return R.fail("你不是该订单的用户,不能进行该操作");
        }
        orderMaster.setOrderStatus((byte) OrderStatus.REFUSE.getKey());
        orderMaster.setUpdateTime(Instant.now());
        orderMasterDao.save(orderMaster);
        addOrderLog(wxUser, orderMaster,"cancel","用户取消订单",orderId,"ok");
        return R.ok();
    }

    public R queryMy(WxUser wxUser, OrderQueryParam orderQueryParam,boolean isJieDan) {
        if (isJieDan  && (wxUser.getUserType() != 2 || wxUser.getOrgId() == null)){
            return R.fail("不能进行该操作");
        }
        StringBuilder dataQuery = new StringBuilder();
        dataQuery.append( "SELECT \n" +
                "    a.`order_id` AS orderId,\n" +
                "    a.`order_no` AS orderNo,\n" +
                "    a.`app_id` AS appId,\n" +
                "    a.`openid` AS openid,\n" +
                "    a.`user_id` AS userId,\n" +
                "    a.`user_mobile` AS userMobile,\n" +
                "    a.`order_status` AS orderStatus,\n" +
                "    a.`total_amount` AS totalAmount,\n" +
                "    a.`pay_amount` AS payAmount,\n" +
                "    a.`discount_amount` AS discountAmount,\n" +
                "    a.`freight_amount` AS freightAmount,\n" +
                "    a.`pay_type` AS payType,\n" +
                "    UNIX_TIMESTAMP(a.`pay_time`)*1000 AS payTime,\n" +
                "    a.`transaction_id` AS transactionId,\n" +
                "    a.`delivery_company` AS deliveryCompany,\n" +
                "    a.`delivery_no` AS deliveryNo,\n" +
                "    UNIX_TIMESTAMP(a.`delivery_time`)*1000 AS deliveryTime,\n" +
                "    UNIX_TIMESTAMP(a.`receive_time`)*1000 AS receiveTime,\n" +
                "    a.`remark` AS remark,\n" +
                "    a.`source` AS source,\n" +
                "    a.`is_deleted` AS isDeleted,\n" +
                "    UNIX_TIMESTAMP(a.`create_time`)*1000 AS createTime,\n" +
                "    UNIX_TIMESTAMP(a.`update_time`)*1000 AS updateTime,\n" +
                "    b.`item_id` AS itemId,\n" +
                "    b.`price` AS price,\n" +
                "    b.`quantity` AS quantity,\n" +
                "    b.`subtotal` AS subtotal,\n" +
                "    b.`refund_status` AS refundStatus,\n" +
                "    b.`refund_amount` AS refundAmount,\n" +
                "    UNIX_TIMESTAMP(b.`refund_time`)*1000 AS refundTime,\n" +
                "    b.`refund_reason` AS refundReason,\n" +
                "    b.`description` AS description,\n" +
                "    b.`address` AS address,\n" +
                "    b.`user_lng` AS userLng,\n" +
                "    b.`user_lat` AS userLat,\n" +
                "    b.`service_sub_category_name` AS serviceSubCategoryName,\n" +
                "    b.`service_sub_category_id` AS serviceSubCategoryId,\n" +
                "    UNIX_TIMESTAMP(b.`appointment_time`)*1000 AS appointmentTime,\n" +
                "    b.`technician_mobile` AS technicianMobile,\n" +
                "    b.`technician_name` AS technicianName,\n" +
                "    b.`technician_id` AS technicianId\n" +
                "FROM order_master a \n" +
                "INNER JOIN order_item b ON a.order_id = b.order_id \n" +
                "where a.is_deleted=0 \n" );

        StringBuilder countQuery = new StringBuilder();
        countQuery.append("SELECT count(*) \n " +
                "FROM order_master a \n " +
                "INNER JOIN order_item b ON a.order_id = b.order_id\n " +
                "where a.is_deleted=0\n " );

        Map<String, Object> params = new HashMap<>();
        Integer page = orderQueryParam.getPage();
        Integer size = orderQueryParam.getSize();
        List<Long> orderStatus = orderQueryParam.getOrderStatus();
        String likeName = orderQueryParam.getLikeName();

        if (isJieDan) {
            dataQuery.append(" and b.`technician_id`=:technicianId ");
            countQuery.append(" and b.`technician_id`=:technicianId ");
            params.put("technicianId", wxUser.getOrgId());
        }else {
            dataQuery.append(" and a.`user_id`=:userId ");
            countQuery.append(" and a.`user_id`=:userId ");
            params.put("userId", wxUser.getId());
        }

        if (orderStatus != null && orderStatus.size() > 0) {
            dataQuery.append(" and a.order_status in (:orderStatus) ");
            countQuery.append( " and a.order_status in (:orderStatus) ");
            params.put("orderStatus", orderStatus);
        }

        if (StringUtils.isNotBlank(likeName)) {
            dataQuery.append(" and (b.technician_name like :likeName or b.service_sub_category_name like :likeName) ");
            countQuery.append(" and (b.technician_name like :likeName or b.service_sub_category_name like :likeName) ");
            params.put("likeName", "%" + likeName + "%");
        }

        //查询总数,如果总数为0，则返回

        Query queryCount = entityManager.createNativeQuery(countQuery.toString());
        // 设置参数
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            queryCount.setParameter(entry.getKey(), entry.getValue());
        }
        long total = ((Number) queryCount.getSingleResult()).longValue();
        if (total == 0) {
            PageInfo pageInfo = new PageInfo<>();
            pageInfo.setPage(page);
            pageInfo.setSize(size);
            pageInfo.setTotal(total);
            pageInfo.setData(new ArrayList<>());
            pageInfo.setTotalPage(0);
            return R.ok(pageInfo);
        }

        // 如果数据不为空,继续查询,添加排序条件
        if (page != null && page >0 && size != null && size > 0) {
            dataQuery.append(" LIMIT " + Math.max(0, (page - 1) * size) + "," + size);
        }
        Query query = entityManager.createNativeQuery(dataQuery.toString());
        // 设置参数
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
        //设置查询结果映射Map
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        // 获取结果
        List<Map<String,Object>> results = query.getResultList();
        PageInfo pageInfo = new PageInfo<>();
        pageInfo.setPage(page);
        pageInfo.setSize(size);
        pageInfo.setTotal(total);
        pageInfo.setData(results);
        pageInfo.setTotalPage(size==null?1:(int) Math.ceil((double) total / size));
        return R.ok(pageInfo);
    }


    public R detail(Long orderId) {
        // 1. 查询订单主表
        OrderMaster orderMaster = orderMasterDao.findById(orderId).orElse(null);
        if (orderMaster != null) {
            R.fail("订单不存在");
        }
        // 2. 查询订单详情
        OrderItem orderItem = orderItemDao.findByOrderId(orderId);
        // 3. 获取评价
        OrderReview orderReview = orderReviewDao.findByOrderId(orderId);
        HashMap<String, Object> map = new HashMap<>();
        map.put("order", orderMaster);
        map.put("orderDetail", orderItem);
        map.put("orderReview", orderReview);
        return R.ok(map);
    }

    @Transactional
    public R addReview(WxUser wxUser, OrderReview orderReview) {
        OrderMaster orderMaster = orderMasterDao.findById(orderReview.getOrderId()).orElse( null);
        if (orderMaster == null) {
            return R.fail("订单不存在");
        }
        if (orderMaster.getOrderStatus() != OrderStatus.PAID.getKey()) {
            return R.fail("订单状态不为待评价");
        }
        if (!orderMaster.getUserId().equals(wxUser.getId())) {
            return R.fail("该订单不属于你");
        }
        OrderReview orderReviewOpt = orderReviewDao.findByOrderId(orderReview.getOrderId());
        if (orderReviewOpt != null) {
            return R.fail("该订单已评价");
        }
        OrderItem orderItem = orderItemDao.findByOrderId(orderReview.getOrderId());
        if (orderItem == null) {
            return R.fail("订单详情不存在");
        }
        orderReview.setUserId(wxUser.getId());
        orderReview.setTechnicianId(orderItem.getTechnicianId());
        orderReview.setServiceSubCategoryName(orderItem.getServiceSubCategoryName());
        orderReview.setCreatedAt(new Date());
        orderReview.setUpdatedAt(new Date());
        orderReview.setStatus(1);// 直接显示
        orderReviewDao.save(orderReview);
        // 修改订单状态
        orderMaster.setOrderStatus((byte) OrderStatus.COMPLETED.getKey());
        orderMasterDao.save(orderMaster);
        return R.ok();
    }
}
